home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 3 / Gold Medal Software - Volume 3 (Gold Medal) (1994).iso / prog / 96cqa.exe / VARRAY.CPP < prev   
C/C++ Source or Header  |  1994-06-01  |  6KB  |  222 lines

  1. ////////////////////////////////////////////////////////////////
  2. // VARRAY.CPP
  3. // This program shows how to implement a dynamic array of objects
  4. // that can be resized in place. To compile:
  5. //
  6. //        bcc varray.cpp                (Borland)
  7. //        cl  varray.cpp                (Microsoft)
  8. //        sc  varray.cpp                (Symantec)
  9.  
  10. #include <stdio.h>
  11. #include <malloc.h>
  12. #include <assert.h>
  13. #include <memory.h>
  14.  
  15. #define TRACE printf                    // For diagnostics
  16.  
  17. //////////////////
  18. // Overloaded operator new operator lets you construct 
  19. // an object at any location in memory.
  20. // 
  21. void* operator new (size_t, void* p) { return p; }
  22.  
  23. //////////////////
  24. // Some class that has a constructor and copy constructor
  25. //
  26. class Foo {
  27.     static int nextID;                // next unique Foo ID
  28.     int id;                                // this object's ID
  29.     char s[12];                            // filler to make sizeof(Foo)=16;
  30. public:
  31.     Foo();                                // normal no-arg constructor
  32.     Foo(const Foo& obj);                // copy constructor
  33.     virtual ~Foo();
  34.     int GetID()    { return id; }
  35. };
  36. int Foo::nextID = 0;                    // instantiate
  37.  
  38. // Default constructor: set ID and display diagnostic
  39. Foo::Foo()
  40. {
  41.     id = ++nextID;
  42.     TRACE("(constructing Foo %2d at %p)\n", id, this);
  43. }
  44.  
  45. // Copy constructor: copy ID and display diagnostic
  46. Foo::Foo(const Foo& obj)
  47. {
  48.     id = obj.id;
  49.     TRACE("(copied Foo from %p to %p)\n", &obj, this);
  50. }
  51.  
  52. // Destructor: display diagnostic
  53. Foo::~Foo()
  54. {
  55.     TRACE("(destroying Foo %2d at %p)\n", id, this);
  56. }
  57.  
  58. //////////////////
  59. // Dynamic array class
  60. //
  61. class Array {
  62.     Foo*        m_pObj;                    // array of Foo objects
  63.     int        m_nObj;                    // number of objects in array
  64.     void ConstructObjs(Foo* pObj, int n);
  65.     void DestroyObjs  (Foo* pObj, int n);
  66.  
  67. public:
  68.     Array(int nObj);
  69.     ~Array();
  70.  
  71.     Foo& operator[] (int i)
  72.         { assert(0<=i && i<m_nObj); return m_pObj[i]; }
  73.     int Size()    
  74.         { return m_nObj; }
  75.     int ReSize(int nObj);
  76. };
  77.  
  78. //////////////////
  79. // Create array of nObj objects
  80. //
  81. Array::Array(int nObj)
  82. {
  83.     m_pObj = (Foo*)malloc(nObj * sizeof(Foo));
  84.     m_nObj = nObj;
  85.     TRACE("Array::Array: allocated %d objects at %p\n", m_nObj, m_pObj);
  86.     ConstructObjs(m_pObj, nObj);
  87. }
  88.  
  89. //////////////////
  90. // Re-size array 
  91. //
  92. int Array::ReSize(int nObj)
  93. {
  94.     assert(m_pObj);
  95.  
  96.     if (nObj < m_nObj) {
  97.         // Shrinking array: destroy dead objects
  98.         TRACE("Array::ReSize: shrinking array to %d objects\n", nObj);
  99.         DestroyObjs(&m_pObj[nObj], m_nObj-nObj);
  100.  
  101.     } else if (nObj > m_nObj) {
  102.         // Array is growing:
  103.         // First see if could realloc in same buffer.
  104.         //
  105.         // This is where knowledge of the memory manager is required:
  106.         // For MSC, true size of block (in small/medium model) is the
  107.         // word preceeding the block's address; for Borland, it's the
  108.         // word before that.
  109.         //
  110.         Foo *pNewObj;
  111. #ifdef __BORLANDC__
  112.         int sizeIHave = *( ((unsigned*)m_pObj)-2 );
  113. #else
  114.         int sizeIHave = *( ((unsigned*)m_pObj)-1 );
  115. #endif
  116.         // Do sanity-check on size
  117.         assert(sizeIHave >= m_nObj*sizeof(Foo));
  118.  
  119.         int sizeIWant = nObj * sizeof(Foo);
  120.         if (sizeIHave>=sizeIWant) {
  121.             // Block is big enough to grow in place: do the realloc
  122.             // 
  123.             TRACE("Array::ReSize: growing array in place to %d objects\n",nObj);
  124.             pNewObj = (Foo*)realloc(m_pObj, sizeIWant);
  125.             assert(pNewObj==m_pObj);
  126.  
  127.         } else {
  128.             // realloc would have to allocate new memory anyway, so do 
  129.             // it myself. Don't call realloc because I need both arrays
  130.             // in place at the same time so I can copy old==>new
  131.             //
  132.             pNewObj = (Foo*)malloc(sizeIWant);
  133.             if (pNewObj==NULL)
  134.                 return 0;                // failed
  135.             
  136.             TRACE("Array::ReSize: allocating new array of %d objects at %p\n", 
  137.                 nObj, pNewObj);
  138.  
  139.             // Copy and destroy the old objects
  140.             // Must do memcpy first to copy address of vtable!
  141.             memcpy(pNewObj, m_pObj, m_nObj*sizeof(Foo));
  142.             for (int i=0; i<m_nObj; i++)
  143.                 new (&pNewObj[i]) Foo(m_pObj[i]);
  144.             DestroyObjs(m_pObj, m_nObj);
  145.  
  146.             // Free the old array
  147.             TRACE("Array::ReSize: freeing old memory at %p\n", m_pObj);
  148.             free(m_pObj);
  149.  
  150.             m_pObj = pNewObj;            // my new array now
  151.         }
  152.  
  153.         // Construct the extra new objects
  154.         ConstructObjs(&pNewObj[m_nObj], nObj-m_nObj);
  155.  
  156.     }
  157.     m_nObj = nObj;
  158.     return 1;                            // success
  159. }
  160.  
  161. //////////////////
  162. // Construct n objects at a given address in memory
  163. //
  164. void Array::ConstructObjs(Foo* pObj, int n)
  165. {
  166.     for (int i=0; i<n; i++)
  167.         new (&pObj[i]) Foo;        // call overloaded new operator
  168. }
  169.  
  170. //////////////////
  171. // Destroy n objects at a given address in memory
  172. //
  173. void Array::DestroyObjs(Foo* pObj, int n)
  174. {
  175.     for (int i=0; i<n; i++)
  176.         pObj[i].Foo::~Foo();    // call destructor explicitly
  177. }
  178.  
  179. //////////////////
  180. // Destroy array: destroy each object, then free their memory
  181. //
  182. Array::~Array()
  183. {
  184.     DestroyObjs(m_pObj, m_nObj);
  185.     TRACE("Array::~Array: destroying memory at %p\n", m_pObj);
  186.     free(m_pObj);
  187.     m_pObj = NULL;                        // safe
  188.     m_nObj = 0;
  189. }
  190.  
  191. //////////////////
  192. // Print contents of array
  193. //
  194. static void PrintArray(Array *pArray)
  195. {
  196.     printf("\nHere's the Array\n================\n");
  197.     for (int i=0; i<pArray->Size(); i++) {
  198.         Foo& obj = (*pArray)[i];
  199.         printf("Object %2d at %p\n", obj.GetID(), &obj);
  200.     }
  201.     printf("\n");
  202. }
  203.  
  204. //////////////////                    
  205. // Array test program: create an array and resize it
  206. //
  207. int main(int, char**)
  208. {
  209.     Array* pArray = new Array(5);
  210.     PrintArray(pArray);
  211.  
  212.     static int NEWSIZE[3] = { 10, 7, 9 };
  213.     for (int i=0; i<3; i++) {
  214.         pArray->ReSize(NEWSIZE[i]);
  215.         PrintArray(pArray);
  216.     }
  217.     printf("Goodbye!\n\n");
  218.     delete pArray;
  219.  
  220.     return 0;
  221. }
  222.